Given a list of integers, find the highest product you can get from three of the integers.
The input list_of_ints will always have at least three integers.
We use a greedy approach to solve the problem in one pass. At each iteration we keep track of:
When we reach the end, the highest_product_of_3 is our answer. We maintain the others because they're necessary for keeping the highest_product_of_3 up to date as we walk through the list. At each iteration, the highest_product_of_3 is the highest of:
def highest_product_of_3(list_of_ints):
if len(list_of_ints) < 3:
raise ValueError('Less than 3 items!')
# We're going to start at the 3rd item (at index 2)
# so pre-populate highests and lowests based on the first 2 items.
# We could also start these as None and check below if they're set
# but this is arguably cleaner
highest = max(list_of_ints[0], list_of_ints[1])
lowest = min(list_of_ints[0], list_of_ints[1])
highest_product_of_2 = list_of_ints[0] * list_of_ints[1]
lowest_product_of_2 = list_of_ints[0] * list_of_ints[1]
# Except this one--we pre-populate it for the first *3* items.
# This means in our first pass it'll check against itself, which is fine.
highest_product_of_3 = list_of_ints[0] * list_of_ints[1] * list_of_ints[2]
# Walk through items, starting at index 2
for i in range(2, len(list_of_ints)):
current = list_of_ints[i]
# Do we have a new highest product of 3?
# It's either the current highest,
# or the current times the highest product of two
# or the current times the lowest product of two
highest_product_of_3 = max(highest_product_of_3,
current * highest_product_of_2,
current * lowest_product_of_2)
# Do we have a new highest product of two?
highest_product_of_2 = max(highest_product_of_2,
current * highest,
current * lowest)
# Do we have a new lowest product of two?
lowest_product_of_2 = min(lowest_product_of_2,
current * highest,
current * lowest)
# Do we have a new highest?
highest = max(highest, current)
# Do we have a new lowest?
lowest = min(lowest, current)
return highest_product_of_3
time and additional space.
Greedy algorithms in action again!
That's not a coincidence—to illustrate how one pattern can be used to break down several different questions, we're showing this one pattern in action on several different questions.
Usually it takes seeing an algorithmic idea from a few different angles for it to really make intuitive sense.
Our goal here is to teach you the right way of thinking to be able to break down problems you haven't seen before. Greedy algorithm design is a big part of that way of thinking.
For this one, we built up our greedy algorithm exactly the same way we did for the Apple stocks question. By asking ourselves:
"Suppose we could come up with the answer in one pass through the input, by simply updating the 'best answer so far' as we went. What additional values would we need to keep updated as we looked at each item in our set, in order to be able to update the 'best answer so far' in constant time?"
For the Apple stocks question, the only "additional value" we needed was the min price so far.
For this one, we needed four things in order to calculate the new highest_product_of_3 at each step:
Do you have an answer?
Wanna review this one again later? Or do you feel like you got it all?
Mark as done Pin for review laterReset editor
Powered by qualified.io